
#include "polyhedra.h"

Polyhedra :: Polyhedra ()
{
	Polyhedra (1.0f);
}

Polyhedra :: Polyhedra(float _size)
{
	Polyhedra (_size, 0, 2.0f);
}

Polyhedra :: Polyhedra (float _size, int _i, float _r)
{
	SetPoint (_size);
	SetI (_i);
	SetR (_r);
	p = NULL;
}

Polyhedra :: ~Polyhedra ()
{
	if (ph)
		glDeleteLists (ph, 1);
}

void Polyhedra :: Draw ()
{
	glCallList (ph);
}

void Polyhedra :: SetPoint (float _size)
{
	SetSize (_size);
}

void Polyhedra :: DisplayPoint (Point& p)
{
	float red, green, blue;

	if (coloringmode == 0 /* Gourand Coloring */)
	{
		switch (colortheme)
		{
		case 0:
			/* HSV Across */
			hsv2rgb ((float)fabs(p.X()), 1.0f, 1.0f, &red, &green, &blue);
			break;
		case 1:
			/* HSV Updown */
			hsv2rgb ((float)fabs(p.Y()), 1.0f, 1.0f, &red, &green, &blue);
			break;
		case 2:
			/* Purple Red */
			rgb2hsv (p.X(), p.Y(), p.Z(), &red, &green, &blue);
			break;
		case 3:
			/* Red and Blue */
			hsv2rgb ((float)(0.5+rand()/(2*(float)RAND_MAX)), 1.0, 1.0, &red, &green, &blue);
			break;
		case 4:
			/* RGB */
			red = p.X() + 0.5f;
			green = p.Y() + 0.5f;
			blue = p.Z() + 0.5f;
			break;
		default:		
			break;
		}
		glColor3f (red, green, blue);
	}
	else
	{
		/* Pre-set coloring */
		glColor3f (this->red, this->green, this->blue);
	}
	glVertex3f (p.X(), p.Y(), p.Z());
}

void Polyhedra :: DrawFace (Point& p1, Point& p2, Point& p3)
{
	Point normal;

	glBegin(GL_TRIANGLES);
		CalcNormal (normal, p1, p2, p3);
		glNormal3f (normal.X(), normal.Y(), normal.Z());
		DisplayPoint (p1);
		DisplayPoint (p2);
		DisplayPoint (p3);
	glEnd();
}

void Polyhedra :: DrawFace (Point& p1, Point& p2, Point& p3,
		Point& p4)
{
	Point normal;

	glBegin(GL_QUADS);
		CalcNormal (normal, p1, p2, p3);
		/* I am using a different normal than should be since
		   the vertices were given in the wrong order. */
		glNormal3f (-normal.X(), -normal.Y(), -normal.Z());
		DisplayPoint (p1);
		DisplayPoint (p2);
		DisplayPoint (p3);
		DisplayPoint (p4);
	glEnd();
}

void Polyhedra :: DrawFace (Point& p1, Point& p2, Point& p3,
							Point& p4, Point& p5)
{
	Point normal;

	glBegin (GL_POLYGON);
		CalcNormal (normal, p1, p2, p3);
		glNormal3f (-normal.X(), -normal.Y(), -normal.Z());
		DisplayPoint (p1);
		DisplayPoint (p2);
		DisplayPoint (p3);
		DisplayPoint (p4);
		DisplayPoint (p5);
	glEnd();
}

void Polyhedra :: _Draw (Point* pts)
{
}

void Polyhedra :: IterDraw ()
{
	Queue<Point*> q;
	Point** p_ptr = new Point*[num_pts];

	for (int loopi=0; loopi<num_pts; loopi++)
	{
		Point* temp = new Point(p[loopi]);
		q.Enqueue ( temp );
	}

	// Iterative method for drawing the tetrahedron
	for (int loopr=0; loopr<i; loopr++)
	{
		int qsize = q.GetSize();
		while (qsize)
		{
			for (int loopi=0; loopi <num_pts; loopi++)
				p_ptr[loopi] = q.Dequeue();
			qsize = qsize - num_pts;
			
			for (int loopj=0; loopj<num_pts; loopj++)
			{
				for (int loopk=0; loopk<num_pts; loopk++)
				{
					Point* apoint = new Point( *(p_ptr[loopj]) + 
						( *(p_ptr[loopk]) - *(p_ptr[loopj]) ) /r);
					if (apoint == NULL)
					{
						// Means we are out of memory
						exit (-1);
					}
					q.Enqueue (apoint);
				}
			}

			for (int loopi=0; loopi<num_pts; loopi++)
				delete p_ptr[loopi];
		}
	}

	Point* tmp_ptr = new Point[num_pts];
	Point* tmp_pt;
	while (!q.IsEmpty())
	{
		for (int loopi=0; loopi <num_pts; loopi++)
		{
			tmp_pt = q.Dequeue();
			tmp_ptr[loopi] = *(tmp_pt);
			delete tmp_pt;
		}
		_Draw (tmp_ptr);
	}
	delete tmp_ptr;

	delete p_ptr;
}

void Polyhedra :: RecurDraw(int i, Point* pts)
{
	if (i == 0)
	{
		_Draw (pts);
	}
	else
	{
		for (int loopi=0; loopi<num_pts; loopi++)
		{
			Point* tmp_pts = new Point[num_pts];
			for (int loopj=0; loopj<num_pts; loopj++)
			{
				tmp_pts[loopj] = pts[loopi] + (pts[loopj]-pts[loopi])/r;
			}

			RecurDraw (i-1, tmp_pts);
			delete tmp_pts;
		}
	}
}

void Polyhedra :: Make ()
{
	ph = glGenLists (1);
	glNewList (ph, GL_COMPILE);
	if (iterative)
		IterDraw();
	else
		RecurDraw (i, p);
	glEndList();
}